/**
 * @file liveroom.js 直播模式房间管理sdk
 * @author binniexu
 */
const webim = require('./webim_wx');
const webimhandler = require('./webim_handler');
const tls = require('./tls');
const encrypt = require('./encrypt');

let serverDomain = '',		// 后台域名
    heart = '',				// 判断心跳变量
    requestSeq = 0,			// 请求id
    requestTask = [],		// 请求task
	// 用户信息
    accountInfo = {
        userID: '',			// 用户ID
        userName: '',		// 用户昵称
        userAvatar: '',		// 用户头像URL
        userSig: '',		// IM登录凭证
        sdkAppID: '',		// IM应用ID
        accountType: '',	// 账号集成类型
        accountMode: 0,		// 帐号模式，0-表示独立模式，1-表示托管模式
        token: '',			// 登录RoomService后使用的票据
    },
	// 房间信息
    roomInfo = {
        roomID: '',			// 视频位房间ID
        roomInfo: '',		// 房间名称
        mixedPlayURL: '', 	// 混流地址
        isCreator: false,	// 是否为创建者
        pushers: [],		// 当前用户信息
        isLoginIM: false,	// 是否登录IM
        isJoinGroup: false,	// 是否加入群
        isDestory: false,	// 是否已解散
        hasJoinPusher: false,
    },
	// 事件
    event = {
        onGetPusherList() {},		// 初始化成员列表
        onPusherJoin() {},			// 进房通知
        onPusherQuit() {},			// 退房通知
        onRoomClose() {},			// 群解散通知
        onRecvRoomTextMsg() {},		// 消息通知
        onRecvJoinPusherRequest() {}, // 大主播收到小主播连麦请求通知
        onKickOut() {}, // 小主播被踢通知
        onRecvRoomCustomMsg() {}, // 自定义消息通知
        onSketchpadData() {},
    };
// 随机昵称
const userName = ['林静晓', '陆杨', '江辰', '付小司', '陈小希', '吴柏松', '肖奈', '芦苇微微', '一笑奈何', '立夏'];
// 请求数
let requestNum = 0;
let requestJoinCallback = null;
let bigAnchorStreamID = '';
let bigAnchorWidth = 360;
let bigAnchorHeight = 640;
let gTimeoutID = null;

/**
 * [request 封装request请求]
 * @param {options}
 *   url: 请求接口url
 *   data: 请求参数
 *   success: 成功回调
 *   fail: 失败回调
 *   complete: 完成回调
 */
function request(options) {
    if (!serverDomain) {
        console.log('请求服务器域名为空，请将wxlite/config里面的url配置成你的服务器域名');
        options.fail && options.fail({
            errCode: -9,
            errMsg: '请求服务器域名为空，请将wxlite/config里面的url配置成你的服务器域名',
        });
        return;
    }
    requestNum++;
  console.log('requestNum: ', requestNum);    requestTask[requestSeq++] = wx.request({
        url: `${serverDomain + options.url + (options.params ? (`?${formatParams(options.params)}&`) : '?')}userID=${accountInfo.userID}${accountInfo.token ? `&token=${accountInfo.token}` : ''}`,
        data: options.data || {},
        method: 'POST',
        header: {
            'content-type': 'application/json', // 默认值
        },
		// dataType: 'json',
        success: options.success || function () {},
        fail: options.fail || function () {},
        complete: options.complete || function () {
            requestNum--;
			// console.log('complete requestNum: ',requestNum);
        },
    });
}

// url encode编码
function formatParams(data) {
    const arr = [];
    for (const name in data) {
        arr.push(`${encodeURIComponent(name)}=${encodeURIComponent(data[name])}`);
    }
    return arr.join('&');
}

/**
 * [login 初始化登录信息]
 * @param {options}
 *   data: {
 *   	serverDomain: 请求域名
 *   }
 *   success: 成功回调
 *   fail: 失败回调
 *
 * @return success
 *   userName: 用户昵称
 */
function login(options) {
    if (!options || !options.data.serverDomain) {
        console.log('init参数错误', options);
        options.fail && options.fail({
            errCode: -9,
            errMsg: 'init参数错误',
        });
        return;
    }
    serverDomain = options.data.serverDomain;
    accountInfo.userID = options.data.userID;
    accountInfo.userSig = options.data.userSig;
    accountInfo.sdkAppID = options.data.sdkAppID;
    accountInfo.accountType = options.data.accType;
  	accountInfo.userName = options.data.userName || userName[Math.floor(Math.random() * 10)] || accountInfo.userID;
    accountInfo.userAvatar = options.data.userAvatar || '123';

    request({
        url: 'login',
        params: {
            accountType: accountInfo.accountType,
            sdkAppID: accountInfo.sdkAppID,
            userSig: accountInfo.userSig,
        },
        data: {},
        success(ret) {
            if (ret.data.code) {
                console.error('登录到RoomService后台失败:', JSON.stringify(ret));
                options.fail && options.fail({
                    errCode: ret.data.code,
                    errMsg: ret.data.message,
                });
                return;
            }
            accountInfo.token = ret.data.token;
            accountInfo.userID = ret.data.userID;
			// 登录IM
	        loginIM({
	        	success(ret) {
            options.success && options.success({
                userID: accountInfo.userID,
                userName: accountInfo.userName,
            });
        },
	        	fail(ret) {
            console.error('IM登录失败:', JSON.stringify(ret));
            options.fail && options.fail({
                errCode: -999,
                errMsg: 'IM登录失败',
            });
        },
	        });
        },
        fail(ret) {
            console.error('登录到RoomService后台失败:', JSON.stringify(ret));
            options.fail && options.fail(ret);
        },
    });
}

/**
 * [logout 结束初始化信息]
 */
function logout() {
    request({
        url: 'logout',
        success(ret) {},
        fail(ret) {},
    });
    serverDomain = '';
    accountInfo.userID = '';
    accountInfo.userSig = '';
    accountInfo.sdkAppID = '';
    accountInfo.accountType = '';
    accountInfo.userName = '';
    accountInfo.userAvatar = '';
    accountInfo.token = '';
	// 退出IM登录
    webimhandler.logout();
}

/**
 * [loginIM 登录IM]
 * @param {options}
 *   data: {
 *   	roomID: 房间ID
 *   }
 *   success: 成功回调
 *   fail: 失败回调
 */
function loginIM(options) {
	// 初始化设置参数
    webimhandler.init({
        accountMode: accountInfo.accountMode,
        accountType: accountInfo.accountType,
        sdkAppID: accountInfo.sdkAppID,
        avChatRoomId: options.roomID || 0,
        selType: webim.SESSION_TYPE.GROUP,
        selToID: options.roomID || 0,
        selSess: null, // 当前聊天会话
    });
	// 当前用户身份
    const loginInfo = {
        sdkAppID: accountInfo.sdkAppID, // 用户所属应用id,必填
        appIDAt3rd: accountInfo.sdkAppID, // 用户所属应用id，必填
        accountType: accountInfo.accountType, // 用户所属应用帐号类型，必填
        identifier: accountInfo.userID, // 当前用户ID,必须是否字符串类型，选填
        identifierNick: accountInfo.userID, // 当前用户昵称，选填
        userSig: accountInfo.userSig, //当前用户身份凭证，必须是字符串类型，选填
    };
	// 监听（多终端同步）群系统消息方法，方法都定义在demo_group_notice.js文件中
    const onGroupSystemNotifys = {
		// 群被解散(全员接收)
        5(notify) {
            roomInfo.isDestory = true;
            event.onRoomClose();
        },
        11: webimhandler.onRevokeGroupNotify, // 群已被回收(全员接收)
		// 用户自定义通知(默认全员接收)
        255(notify) {
			// console.error('收到系统通知：', notify.UserDefinedField);
            const content = JSON.parse(notify.UserDefinedField);
            if (content && content.cmd == 'notifyPusherChange') {
                mergePushers();
            }
        },
    };

	// 监听连接状态回调变化事件
    const onConnNotify = function (resp) {
        switch (resp.ErrorCode) {
            case webim.CONNECTION_STATUS.ON:
				// webim.Log.warn('连接状态正常...');
                break;
            case webim.CONNECTION_STATUS.OFF:
                webim.Log.warn('连接已断开，无法收到新消息，请检查下你的网络是否正常');
                break;
            default:
                webim.Log.error(`未知连接状态,status=${resp.ErrorCode}`);
                break;
        }
    };

	// 监听事件
    const listeners = {
        onConnNotify: webimhandler.onConnNotify, // 选填
        onBigGroupMsgNotify(msg) {
            webimhandler.onBigGroupMsgNotify(msg, (msgs) => {
                receiveMsg(msgs);
            }, (datas) => {
                // 收到白板数据
                console.log('LiveRoom callback --> 收到白板数据');
                onSketchpadData(datas);
            });
			// webimhandler.onBigGroupMsgNotify(msg, function (msgs) {
			// 	receiveMsg(msgs);
			// })
        }, // 监听新消息(大群)事件，必填
        onMsgNotify(newMsgList) { // 监听新消息(私聊(包括普通消息和全员推送消息)，普通群(非直播聊天室)消息)事件，必填
            webimhandler.onMsgNotify(newMsgList, (msg) => {
                recvC2CMsg(msg);
            });
        },
        onGroupSystemNotifys, // 监听（多终端同步）群系统消息事件，必填
        onGroupInfoChangeNotify: webimhandler.onGroupInfoChangeNotify,
		// 'onKickedEventCall': self.onKickedEventCall // 踢人操作
    };

	// 其他对象，选填
    const others = {
        isAccessFormalEnv: true, // 是否访问正式环境，默认访问正式，选填
        isLogOn: false, // 是否开启控制台打印日志,默认开启，选填
    };

    if (accountInfo.accountMode == 1) { // 托管模式
        webimhandler.sdkLogin(loginInfo, listeners, others, 0, afterLoginIM, options);
    } else { // 独立模式
		// sdk登录
        webimhandler.sdkLogin(loginInfo, listeners, others, 0, afterLoginIM, options);
    }
}
function afterLoginIM(options) {
    if (options.errCode) {
		// webim登录失败
        console.log('webim登录失败:', options);
        options.callback.fail && options.callback.fail({
            errCode: -2,
            errMsg: 'IM登录失败，如果你是在配置线上环境，请将IM域名[https://webim.tim.qq.com]配置到小程序request合法域名',
        });
        return;
    }
	// webim登录成功
    console.log('webim登录成功');
    roomInfo.isLoginIM = true;
    options.callback.success && options.callback.success({
        userName: accountInfo.userName,
    });
}
function afterJoinBigGroup(options) {
    if (options.errCode) {
        console.log('webim进群失败: ', options);
        options.callback.fail && options.callback.fail({
            errCode: -2,
            errMsg: 'IM进群失败',
        });
        return;
    }
    roomInfo.isJoinGroup = true;
    console.log('进入IM房间成功: ', roomInfo.roomID);
    options.callback.success && options.callback.success({});
}

function onSketchpadData(data) {
    event.onSketchpadData(data);
}

/**
 * [receiveMsg 接收消息处理]
 * @param {options}
 *
 * @return event.onRecvRoomTextMsg
 *   roomID: 房间ID
 *   userID: 用户ID
 *   nickName: 用户昵称
 *   headPic: 用户头像
 *   textMsg: 文本消息
 *   time: 消息时间
 */
function receiveMsg(msg) {
    if (!msg.content) { return; }
    console.log('IM消息: ', JSON.stringify(msg));
    let time = new Date();
    let h = `${time.getHours()}`,
        m = `${time.getMinutes()}`,
        s = `${time.getSeconds()}`;
    h.length == 1 ? (h = `0${h}`) : '';
    m.length == 1 ? (m = `0${m}`) : '';
    s.length == 1 ? (s = `0${s}`) : '';
    time = `${h}:${m}:${s}`;
    msg.time = time;

    if (msg.fromAccountNick == '@TIM#SYSTEM') {
        msg.fromAccountNick = '';
        msg.content = msg.content.split(';');
        msg.content = msg.content[0];
        event.onRecvRoomTextMsg && event.onRecvRoomTextMsg({
            roomID: roomInfo.roomID,
            userID: msg.fromAccountNick,
            userName: msg.userName,
            userAvatar: msg.userAvatar,
            message: msg.content,
            time: msg.time,
        });
    } else {
        let contentObj,
            newContent;
        newContent = msg.content.split('}}');
        contentObj = JSON.parse(`${newContent[0]}}}`);
        if (contentObj.cmd == 'CustomTextMsg') {
            msg.userName = contentObj.data.nickName;
            msg.userAvatar = contentObj.data.headPic;
            var content = '';
            for (var i = 1; i < newContent.length; i++) {
                if (i == newContent.length - 1)					{ content += newContent[i]; } else content += `${newContent[i]}}}`;
            }
            msg.content = content;
            event.onRecvRoomTextMsg && event.onRecvRoomTextMsg({
                roomID: roomInfo.roomID,
                userID: msg.fromAccountNick,
                userName: msg.userName,
                userAvatar: msg.userAvatar,
                message: msg.content,
                time: msg.time,
                isFollow: contentObj.data.isFollow,
            });
        } else if (contentObj.cmd == 'CustomCmdMsg') {
            msg.userName = contentObj.data.nickName;
            msg.userAvatar = contentObj.data.headPic;
            msg.cmd = contentObj.data.cmd;
            var content = '';
            for (var i = 1; i < newContent.length; i++) {
                if (i == newContent.length - 1)					{ content += newContent[i]; } else content += `${newContent[i]}}}`;
            }
            msg.content = content;
            event.onRecvRoomCustomMsg && event.onRecvRoomCustomMsg({
                roomID: roomInfo.roomID,
                userID: msg.fromAccountNick,
                userName: msg.userName,
                userAvatar: msg.userAvatar,
                cmd: msg.cmd,
                message: msg.content,
                time: msg.time,
                isFollow: contentObj.data.isFollow,
            });
        }
    }
}

function recvC2CMsg(msg) {
    console.log('收到C2C消息:', JSON.stringify(msg));
    const contentObj = JSON.parse(msg.content);
    if (contentObj) {
        if (contentObj.cmd == 'linkmic') {
            if (contentObj.data.type && contentObj.data.type == 'request') {
                event.onRecvJoinPusherRequest({
                    userID: msg.fromAccountNick,
                    userName: contentObj.data.userName,
                    userAvatar: contentObj.data.userAvatar,
                });
            } else if (contentObj.data.type && contentObj.data.type == 'response') {
                if (contentObj.data.result == 'accept') {
                    requestJoinCallback && requestJoinCallback({
                        errCode: 0,
                        errMsg: '',
                    });
                } else if (contentObj.data.result == 'reject') {
                    requestJoinCallback && requestJoinCallback({
                        errCode: -999,
                        errMsg: '主播拒绝了你的请求',
                    });
                }
            } else if (contentObj.data.type && contentObj.data.type == 'kickout') {
                event.onKickOut && event.onKickOut({
                    roomID: contentObj.data.roomID,
                });
            }
        }
    }
}

function mergePushers() {
    if (!roomInfo.hasJoinPusher) {
        return;
    }
    getPushers({
        data: {
            roomID: roomInfo.roomID,
        },
        success(ret) {
            ret = ret.data;
			/**
			 * enterPushers：新进推流人员信息
			 * leavePushers：退出推流人员信息
			 * ishave：用于判断去重操作
			 */
            let enterPushers = [],
                leavePushers = [],
                ishave = 0;
            console.log('去重操作');
            console.log('旧', JSON.stringify(roomInfo.pushers));
            console.log('新', JSON.stringify(ret.pushers));
            console.log('用户信息:', JSON.stringify(accountInfo));
            ret.pushers && ret.pushers.forEach((val1) => {
                ishave = 0;
                roomInfo.pushers && roomInfo.pushers.forEach((val2) => {
                    if (val1.userID == val2.userID) {
                        ishave = 1;
                    }
                });
                if (!ishave && val1.userID != accountInfo.userID)					{ enterPushers.push(val1); }
                ishave = 0;
            });
            roomInfo.pushers && roomInfo.pushers.forEach((val1) => {
                ishave = 0;
			    ret.pushers && ret.pushers.forEach((val2) => {
        if (val1.userID == val2.userID) {
            ishave = 1;
        }
    });
                if (!ishave)					{ leavePushers.push(val1); }
                ishave = 0;
            });
			// 重置roomInfo.pushers
            roomInfo.pushers = ret.pushers;
			// 通知有人进入房间
            if (enterPushers.length) {
                console.log('进房:', JSON.stringify(enterPushers));
                event.onPusherJoin && event.onPusherJoin({
                    pushers: enterPushers,
                });
				// 混流
                mergeStream(1);
            }
			// 通知有人退出房间
            if (leavePushers.length) {
                console.log('退房:', JSON.stringify(leavePushers));
                event.onPusherQuit && event.onPusherQuit({
                    pushers: leavePushers,
                });
				// 混流
                mergeStream(1);
            }
        },
        fail(ret) {
			// event.onRoomClose && event.onRoomClose({
			// 	errCode: ret.errCode,
			// 	errMsg: ret.errMsg
			// });
        },
    });
}


function getPushers(object) {
    // 获取房间信息
    request({
        url: 'get_pushers',
        data: {
            roomID: object.data.roomID,
        },
        success(ret) {
            if (ret.data.code) {
                console.log('请求CGI:get_pushers失败', ret);
                object.fail && object.fail({ errCode: ret.data.code, errMsg: `请求CGI:get_pushers失败:${ret.data.message}${+'['}${ret.data.code}]` });
                return;
            }
            console.log('房间信息：', JSON.stringify(ret));
            object.success && object.success(ret);
        },
        fail: object.fail,
    });
}

/**
 * [sendRoomTextMsg 发送文本消息]
 * @param {options}
 *   data: {
 *   	msg: 文本消息
 *   }
 */
function sendRoomTextMsg(options) {
    if (!options || !options.data.msg || !options.data.msg.replace(/^\s*|\s*$/g, '')) {
        console.log('sendRoomTextMsg参数错误', options);
        options.fail && options.fail({
            errCode: -9,
            errMsg: 'sendRoomTextMsg参数错误',
        });
        return;
    }
    webimhandler.sendCustomMsg({
        data: `{"cmd":"CustomTextMsg","data":{"nickName":"${accountInfo.userName}","headPic":"${accountInfo.userAvatar}","isFollow": "${options.isFollow}"}}`,
        text: options.data.msg,
    }, () => {
        options.success && options.success();
    });
}

/**
 * [pusherHeartBeat 推流者心跳]
 * @param {options}
 */
function pusherHeartBeat(options) {
    if (options) {
        setTimeout(() => {
            proto_pusherHeartBeat();
        }, 3000);
    }
    if (heart) {
        setTimeout(() => {
            proto_pusherHeartBeat();
            pusherHeartBeat();
        }, 7000);
    }
}
function proto_pusherHeartBeat() {
    console.log('心跳请求');
    request({
        url: 'pusher_heartbeat',
        data: {
            roomID: roomInfo.roomID,
            userID: accountInfo.userID,
        },
        success(ret) {
            if (ret.data.code) {
                console.log('心跳失败：', ret);
                return;
            }
            console.log('心跳成功', ret);
        },
        fail(ret) {
            console.log('心跳失败：', ret);
        },
    });
}

/**
 * [stopPusherHeartBeat 停止推流者心跳]
 * @param {options}
 */
function stopPusherHeartBeat() {
    heart = false;
}

/**
 * [getRoomList 获取房间列表]
 * @param {options}
 *   data: {
 *   	index: 获取的房间开始索引，从0开始计算
 *   	cnt: 获取的房间个数
 *   }
 *   success: 成功回调
 *   fail: 失败回调
 *
 * @return success
 *   rooms: 房间列表信息
 */
function getRoomList(options) {
    if (!options) {
        console.log('getRoomList参数错误', options);
        options.fail && options.fail({
            errCode: -9,
            errMsg: 'getRoomList参数错误',
        });
        return;
    }
    request({
        url: 'get_room_list',
        data: {
            index: options.data.index || 0,
            cnt: options.data.cnt || 20,
        },
        success(ret) {
            if (ret.data.code) {
                console.error('获取房间列表失败: ', ret);
                options.fail && options.fail({
                    errCode: ret.data.code,
                    errMsg: `${ret.data.message}[${ret.data.code}]`,
                });
                return;
            }
            console.log('房间列表信息:', ret);
            options.success && options.success({
                rooms: ret.data.rooms,
            });
        },
        fail(ret) {
            console.log('获取房间列表失败: ', ret);
            if (ret.errMsg == 'request:fail timeout') {
                var errCode = -1;
                var errMsg = '网络请求超时，请检查网络状态';
            }
            options.fail && options.fail({
                errCode: errCode || -1,
                errMsg: errMsg || '获取房间列表失败',
            });
        },
    });
}


/**
 * [getPushURL 获取推流地址]
 * @param {options}
 *   success: 成功回调
 *   fail: 失败回调
 *
 * @return success
 *   pushURL: 推流地址
 */
function getPushURL(options) {
    if (!options) {
        console.log('getPushURL参数错误', options);
        options.fail && options.fail({
            errCode: -9,
            errMsg: 'getPushURL参数错误',
        });
        return;
    }
    request({
        url: 'get_push_url',
        data: {
            userID: accountInfo.userID,
        },
        success(ret) {
            if (ret.data.code) {
                console.log('获取推流地址失败: ', ret);
                options.fail && options.fail({
                    errCode: ret.data.code,
                    errMsg: `${ret.data.message}[${ret.data.code}]`,
                });
                return;
            }
            console.log('获取推流地址成功：', ret.data.pushURL);
            options.success && options.success({
                pushURL: ret.data.pushURL,
            });
        },
        fail(ret) {
            if (ret.errMsg == 'request:fail timeout') {
                var errCode = -1;
                var errMsg = '网络请求超时，请检查网络状态';
            }
            options.fail && options.fail({
                errCode: errCode || -1,
                errMsg: errMsg || '获取推流地址失败',
            });
        },
    });
}


/**
 * [setListener 设置监听事件]
 * @param {options}
 *   onRoomClose: 群解散通知
 *   onRecvRoomTextMsg: 消息通知
 */
function setListener(options) {
    if (!options) { console.log('setListener参数错误', options); return; }
    event.onGetPusherList = options.onGetPusherList || function () {};
    event.onPusherJoin = options.onPusherJoin || function () {};
    event.onPusherQuit = options.onPusherQuit || function () {};
    event.onRoomClose = options.onRoomClose || function () {};
    event.onRecvRoomTextMsg = options.onRecvRoomTextMsg || function () {};
    event.onRecvJoinPusherRequest = options.onRecvJoinPusherRequest || function () {};
    event.onKickOut = options.onKickOut || function () {};
    event.onRecvRoomCustomMsg = options.onRecvRoomCustomMsg || function () {};
    event.onSketchpadData = options.onSketchpadData || function () {};
}

/**
 * [createRoom 创建房间]
 * @param {options}
 *   data: {
 *   	roomInfo: 房间名称
 *    	pushURL: 推流地址
 *   }
 *   success: 成功回调
 *   fail: 失败回调
 */
function createRoom(options) {
    roomInfo.isCreator = true;
    roomInfo.isDestory = false;
    roomInfo.isJoinGroup = false;
    if (!options || !options.data.roomInfo || !options.data.pushURL) {
        console.log('createRoom参数错误', options);
        options.fail && options.fail({
            errCode: -9,
            errMsg: 'createRoom参数错误',
        });
        return;
    }
    roomInfo.roomInfo = options.data.roomInfo;
    proto_createRoom(options);
}
function get_custom_info(roomID) {
    request({
        url: 'get_custom_info',
        data: {
            roomID
        },
        success(ret) {
            console.log(3333, ret);
        },
        fail(ret) {
            console.log(44, ret);
        },
    });
}
function proto_createRoom(options) {
    request({
        url: 'create_room',
        data: {
            userID: accountInfo.userID,
            roomInfo: roomInfo.roomInfo,
        },
        success(ret) {
            if (ret.data.code) {
                console.log('创建房间失败:', ret);
                options.fail && options.fail({
                    errCode: ret.data.code,
                    errMsg: `${ret.data.message}[${ret.data.code}]`,
                });
                return;
            }
            console.log('--->创建房间成功:', ret);
            roomInfo.roomID = ret.data.roomID;
            roomInfo.roomCreator = accountInfo.userID;
            if (roomInfo.isDestory) {
                roomInfo.isDestory = false;
                destoryRoom({});
                return;
            }
            options.data.roomID = ret.data.roomID;
			// 进入IM群
            webimhandler.applyJoinBigGroup(roomInfo.roomID, afterJoinBigGroup, {
                success() {
                    joinPusher(options);
                },
                fail: options.fail,
            });
        },
        fail(ret) {
            console.log('创建后台房间失败:', ret);
            if (ret.errMsg == 'request:fail timeout') {
                var errCode = -1;
                var errMsg = '网络请求超时，请检查网络状态';
            }
            options.fail && options.fail({
                errCode: errCode || -3,
                errMsg: errMsg || '创建房间失败',
            });
        },
    });
}

/**
 * [joinPusher 加入推流]
 * @param {options}
 *   data: {
 *   	roomID: 房间ID
 *   	pushURL: 推流地址
 *   }
 *   success: 成功回调
 *   fail: 失败回调
 */
function joinPusher(options) {
    if (!options || !options.data.roomID || !options.data.pushURL) {
        console.log('joinPusher参数错误', options);
        options.fail && options.fail({
            errCode: -9,
            errMsg: 'joinPusher参数错误',
        });
        return;
    }
    roomInfo.roomID = options.data.roomID;
  	roomInfo.isDestory = false;
    proto_joinPusher(options);
}
function proto_joinPusher(options) {
    request({
        url: 'add_pusher',
        data: {
            roomID: roomInfo.roomID,
            userID: accountInfo.userID,
            userName: accountInfo.userName,
            userAvatar: accountInfo.userAvatar,
            pushURL: options.data.pushURL,
        },
        success(ret) {
            if (ret.data.code) {
                console.log('进入房间失败:', ret);
                options.fail && options.fail({
                    errCode: ret.data.code,
                    errMsg: `${ret.data.message}[${ret.data.code}]`,
                });
                return;
            }
            roomInfo.hasJoinPusher = true;
            mergePushers();
            console.log('加入推流成功');
			// 开始心跳
            heart = true;
            pusherHeartBeat(1);
  		options.success && options.success({ roomID: roomInfo.roomID });
        },
        fail(ret) {
            console.log('进入房间失败:', ret);
            if (ret.errMsg == 'request:fail timeout') {
                var errCode = -1;
                var errMsg = '网络请求超时，请检查网络状态';
            }
            options.fail && options.fail({
                errCode: errCode || -4,
                errMsg: errMsg || '进入房间失败',
            });
        },
    });
}

/**
 * [enterRoom 进入房间]
 * @param {options}
 *   data: {
 *   	roomID: 房间ID
 *   }
 *   success: 成功回调
 *   fail: 失败回调
 */
function enterRoom(options) {
    roomInfo.isCreator = false;
    roomInfo.isJoinGroup = false;
    if (!options || !options.data.roomID) {
        console.log('enterRoom参数错误', options);
        options.fail && options.fail({
            errCode: -9,
            errMsg: 'enterRoom参数错误',
        });
        return;
    }
    roomInfo.roomID = options.data.roomID;
    proto_enterRoom(options);
}
function proto_enterRoom(options) {
    console.log('开始IM: ', roomInfo.roomID);
    webimhandler.applyJoinBigGroup(roomInfo.roomID, afterJoinBigGroup, {
        success(ret) {
            getPushers({
                data: {
                    roomID: roomInfo.roomID,
                },
                success(ret) {
                    roomInfo.roomID = ret.data.roomID;
                	roomInfo.roomInfo = ret.data.roomInfo;
                	roomInfo.roomCreator = ret.data.roomCreator;
                    roomInfo.mixedPlayURL = ret.data.mixedPlayURL;
                    options.success && options.success({
                        roomID: roomInfo.roomID,
                        mixedPlayURL: roomInfo.mixedPlayURL,
                        pushers: ret.data.pushers,
                    });
                },
                fail(ret) {
                    options.fail && options.fail({
                        errCode: ret.errCode,
                        errMsg: ret.errMsg || '拉取主播信息失败',
                    });
                },
            });
        },
        fail: options.fail,
    });
}

/**
 * [clearRequest 中断请求]
 * @param {options}
 */
function clearRequest() {
    for (let i = 0; i < requestSeq; i++) {
        requestTask[i].abort();
    }
    requestTask = [];
    requestSeq = 0;
}

/**
 * [exitRoom 退出房间]
 * @param {options}
 */
function exitRoom(options) {
    if (roomInfo.isCreator) {
        destoryRoom(options);
    } else {
        leaveRoom(options);
    }
    roomInfo.isDestory = true;
    roomInfo.roomID = '';
    roomInfo.pushers = [];
    roomInfo.mixedPlayURL = '';
    roomInfo.roomInfo = '';
    accountInfo.pushURL = '';
    accountInfo.isCreator = false;
}

/**
 * [leaveRoom 退出房间]
 */
function leaveRoom(options) {
	// 停止心跳
    stopPusherHeartBeat();
	// clearRequest();
    roomInfo.isJoinGroup && webimhandler.quitBigGroup();
    request({
        url: 'delete_pusher',
        data: {
            roomID: roomInfo.roomID,
            userID: accountInfo.userID,
        },
        success(ret) {
            if (ret.data.code) {
                console.log('退出推流失败:', ret);
                console.error(`退房信息: roomID:${roomInfo.roomID}, userID:${accountInfo.userID}`);
                options.fail && options.fail({
                    errCode: ret.data.code,
                    errMsg: `${ret.data.message}[${ret.data.code}]`,
                });
                return;
            }
            console.log('退出推流成功');
            roomInfo.roomID = '';
            options.success && options.success({});
        },
        fail(ret) {
            console.log('退出推流失败:', ret);
            let errCode = ret.errCode || -1;
            let errMsg = ret.errMsg || '退出房间失败';
            if (ret.errMsg == 'request:fail timeout') {
                errCode = -1;
                errMsg = '网络请求超时，请检查网络状态';
            }
            options.fail && options.fail({
                errCode,
                errMsg,
            });
        },
    });
}

/**
 * [destoryRoom 销毁房间]
 */
function destoryRoom(options) {
	// 停止心跳
    stopPusherHeartBeat();
	// clearRequest();
    roomInfo.isJoinGroup && webimhandler.quitBigGroup();
    if (roomInfo.isDestory) return;
    request({
        url: 'destroy_room',
        data: {
            roomID: roomInfo.roomID,
            userID: accountInfo.userID,
        },
        success(ret) {
            if (ret.data.code) {
                console.log('关闭房间失败:', ret);
                console.error(`关闭房间失败: roomID:${roomInfo.roomID}, userID:${accountInfo.userID}`);
                options.fail && options.fail({
                    errCode: ret.data.code,
                    errMsg: `${ret.data.message}[${ret.data.code}]`,
                });
                return;
            }
            console.log('关闭房间成功');
            roomInfo.roomID = '';
            options.success && options.success({});
        },
        fail(ret) {
            console.log('关闭房间失败:', ret);
            let errCode = ret.errCode || -1;
            let errMsg = ret.errMsg || '关闭房间失败';
            if (ret.errMsg == 'request:fail timeout') {
                errCode = -1;
                errMsg = '网络请求超时，请检查网络状态';
            }
            options.fail && options.fail({
                errCode,
                errMsg,
            });
        },
    });
}

function quitPusher(options) {
    stopPusherHeartBeat();
    request({
        url: 'delete_pusher',
        data: {
            roomID: roomInfo.roomID,
            userID: accountInfo.userID,
        },
        success(ret) {
            if (ret.data.code) {
                console.log('退出推流失败:', ret);
                options.fail && options.fail({
                    errCode: ret.data.code,
                    errMsg: `${ret.data.message}[${ret.data.code}]`,
                });
                return;
            }
            console.log('退出推流成功');
            roomInfo.roomID = '';
            roomInfo.pushers = [];
            options.success && options.success({});
        },
        fail(ret) {
            console.log('退出推流失败:', ret);
            if (ret.errMsg == 'request:fail timeout') {
                var errCode = -1;
                var errMsg = '网络请求超时，请检查网络状态';
            }
            options.fail && options.fail({
                errCode: errCode || -1,
                errMsg: errMsg || '退出房间失败',
            });
        },
    });
    roomInfo.hasJoinPusher = false;
}

function requestJoinPusher(object) {
    const body = {
        cmd: 'linkmic',
        data: {
            type: 'request',
            roomID: roomInfo.roomID,
            userID: accountInfo.userID,
            userName: accountInfo.userName,
            userAvatar: accountInfo.userAvatar,
        },
    };

    requestJoinCallback = function (ret) {
        if (gTimeoutID) {
            clearTimeout(gTimeoutID);
            gTimeoutID = null;
        }
        if (ret.errCode) {
            object.fail && object.fail(ret);
        } else {
            object.success && object.success(ret);
        }
    };

    let isTimeout = false;
    gTimeoutID = setTimeout(() => {
        gTimeoutID = null;
        console.error('申请连麦超时:', JSON.stringify(object.data));
        isTimeout = true;
        requestJoinCallback && requestJoinCallback({
            errCode: -999,
            errMsg: '申请加入连麦超时',
        });
    }, (object.data && object.data.timeout) ? object.data.timeout : 30000);

    const msg = {
        data: JSON.stringify(body),
    };
    webimhandler.sendC2CCustomMsg(roomInfo.roomCreator, msg, (ret) => {
        if (isTimeout) {
            return;
        }
        if (ret && ret.errCode) {
            console.log('请求连麦失败:', JSON.stringify(ret));
            requestJoinCallback && requestJoinCallback(ret);
        }
    });
}

function acceptJoinPusher(object) {
    const body = {
        cmd: 'linkmic',
        data: {
            type: 'response',
            result: 'accept',
            message: '',
            roomID: roomInfo.roomID,
        },
    };

    const msg = {
        data: JSON.stringify(body),
    };
    webimhandler.sendC2CCustomMsg(object.data.userID, msg, (ret) => {});
}

function rejectJoinPusher(object) {
    const body = {
        cmd: 'linkmic',
        data: {
            type: 'response',
            result: 'reject',
            message: object.data.reason || '',
            roomID: roomInfo.roomID,
        },
    };

    const msg = {
        data: JSON.stringify(body),
    };
    webimhandler.sendC2CCustomMsg(object.data.userID, msg, (ret) => {});
}

function kickoutSubPusher(object) {
    const body = {
        cmd: 'linkmic',
        data: {
            type: 'kickout',
            roomID: roomInfo.roomID,
        },
    };

    const msg = {
        data: JSON.stringify(body),
    };
    webimhandler.sendC2CCustomMsg(object.data.userID, msg, (ret) => {
        if (ret && ret.errCode == 0) {
            object.success && object.success(ret);
        } else {
            object.fail && object.fail(ret);
        }
    });
}

function getAccountInfo() {
    return accountInfo;
}

/**
 *
 * @param {Int} retryCount
 */
function mergeStream(retryCount) {
    if (accountInfo.userID != roomInfo.roomCreator) {
        // 大主播才能混流
        return;
    }
    const mergeStreams = [];
    if (roomInfo.pushers && roomInfo.pushers.length > 0) {
        roomInfo.pushers.forEach((val) => {
            if (val.userID != roomInfo.roomCreator) {
				// 获取流id
                const streamID = getStreamIDByStreamUrl(val.accelerateURL);
                if (streamID) {
                    mergeStreams.push({
                        userID: val.userID,
                        streamID,
                        width: val.width,
                        height: val.height,
                    });
                }
            } else {
                bigAnchorStreamID = getStreamIDByStreamUrl(val.accelerateURL);
            }
        });
    }
    console.log('混流信息:', JSON.stringify(mergeStreams));

    sendStreamMergeRequest(retryCount, mergeStreams);
}

function getStreamIDByStreamUrl(streamUrl) {
    if (!streamUrl) {
        return null;
    }
    // 推流地址格式: rtmp://8888.livepush.myqcloud.com/path/8888_test_12345?txSecret=aaa&txTime=bbb
    // 拉流地址格式: rtmp://8888.livepush.myqcloud.com/path/8888_test_12345
    //             http://8888.livepush.myqcloud.com/path/8888_test_12345.flv
    //             http://8888.livepush.myqcloud.com/path/8888_test_12345.m3u8

    let subStr = streamUrl;
    let index = subStr.indexOf('?');
    if (index >= 0) {
        subStr = subStr.substring(0, index);
    }
    if (!subStr) {
        return null;
    }
    index = subStr.lastIndexOf('/');
    if (index >= 0) {
        subStr = subStr.substring(index + 1);
    }
    if (!subStr) {
        return null;
    }
    index = subStr.indexOf('.');
    if (index >= 0) {
        subStr = subStr.substring(0, index);
    }
    if (!subStr) {
        return null;
    }
    return subStr;
}

function sendStreamMergeRequest(retryCount, mergeStreams) {
    if (retryCount < 0) {
        return;
    }

    const mergeInfo = createMergeInfo(mergeStreams);
    console.log('混流信息:', JSON.stringify(mergeInfo));

    doMergeRequest(mergeInfo, (ret) => {
        if (ret) {
            console.log('混流成功');
        } else {
            console.log('混流失败');
            setTimeout(() => {
                retryCount--;
                sendStreamMergeRequest(retryCount, mergeStreams);
            }, 2000);
        }
    });
}

function doMergeRequest(mergeInfo, callback) {
    request({
        url: 'merge_stream',
        data: {
            userID: accountInfo.userID,
            roomID: roomInfo.roomID,
            mergeParams: JSON.stringify(mergeInfo),
        },
        success(ret) {
            if (ret.data.code || ret.data.result.code) {
                console.error('混流失败:', JSON.stringify(ret));
                callback(false);
                return;
            }
            callback(true);
        },
        fail(ret) {
            callback(false);
        },
    });
}

function createMergeInfo(mergeStreams) {
    console.log('混流原始信息:', JSON.stringify(mergeStreams));

    let smallAnchorWidth = 160;
    let smallAnchorHeight = 240;
    let offsetHeight = 90;
    if (bigAnchorWidth < 540 || bigAnchorHeight < 960) {
        smallAnchorWidth = 120;
        smallAnchorHeight = 180;
        offsetHeight = 60;
    }

    // 组装混流JSON结构体
    const streamInfoArray = [];
    if (mergeStreams && mergeStreams.length > 0) {
        // 大主播
        var bigAnchorInfo = {
            input_stream_id: bigAnchorStreamID || '',
            layout_params: {
                image_layer: 1,
            },
        };
        streamInfoArray.push(bigAnchorInfo);

        // 小主播
        const subLocationX = bigAnchorWidth - smallAnchorWidth;
        const subLocationY = bigAnchorHeight - smallAnchorHeight - offsetHeight;
        if (mergeStreams && mergeStreams.length > 0) {
            let layerIndex = 0;
            mergeStreams.forEach((val) => {
				// 组装JSON
                const smallAchorInfo = {
                    input_stream_id: val.streamID,
                    layout_params: {
                        image_layer: layerIndex + 2,
                        image_width: smallAnchorWidth,
                        image_height: smallAnchorHeight,
                        location_x: subLocationX,
                        location_y: subLocationY - layerIndex * smallAnchorHeight,
                    },
                };
                streamInfoArray.push(smallAchorInfo);
                layerIndex++;
            });
        }
    } else {
        var bigAnchorInfo = {
            input_stream_id: bigAnchorStreamID || '',
            layout_params: {
                image_layer: 1,
            },
        };
        streamInfoArray.push(bigAnchorInfo);
    }

    const para = {
        app_id: accountInfo.sdkAppID.toString(),
        interface: 'mix_streamv2.start_mix_stream_advanced',
        mix_stream_session_id: bigAnchorStreamID,
        output_stream_id: bigAnchorStreamID,
        input_stream_list: streamInfoArray,
    };

    const interfaceObj = {
        interfaceName: 'Mix_StreamV2',
        para,
    };

    const reqParam = {
        timestamp: Math.round((Date.now() / 1000)),
        eventId: Math.round((Date.now() / 1000)),
        interface: interfaceObj,
    };

    return reqParam;
}

function setVideoRatio(ratio) {
    if (ratio == 1) {
		// 9:16
        bigAnchorWidth = 360;
        bigAnchorHeight = 640;
    } else {
		// 3:4
        bigAnchorWidth = 480;
        bigAnchorHeight = 640;
    }
}

/**
 * 对外暴露函数
 * @type {Object}
 */
module.exports = {
    login,							// 初始化
    logout,						// 结束初始化
    getRoomList,			// 拉取房间列表
    getPushURL,				// 拉取推流地址
    createRoom,				// 创建房间
    enterRoom,				// 加入房间
    exitRoom,					// 退出房间
    sendRoomTextMsg,	// 发送文本消息
    setListener,			// 设置监听事件
    joinPusher,
    quitPusher,
    requestJoinPusher,
    acceptJoinPusher,
    rejectJoinPusher,
    kickoutSubPusher,
    getAccountInfo,
    get_custom_info,
    setVideoRatio,
	// addRemoteView: addRemoteView,
	// deleteRemoteView: deleteRemoteView
};
